package com.offics.loan.domain.service;

import com.offics.loan.domain.entity.Loan;
import com.offics.loan.domain.entity.LoanProduct;
import com.offics.loan.domain.entity.RepaymentPlan;
import com.offics.loan.domain.repository.LoanProductRepository;
import com.offics.loan.domain.repository.LoanRepository;
import com.offics.loan.domain.repository.RepaymentPlanRepository;
import com.offics.loan.domain.repository.UserRepository;
import com.offics.loan.infrastructure.exception.BusinessException;
import com.offics.loan.infrastructure.common.ResultCode;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 贷款领域服务
 */
@Service
@RequiredArgsConstructor
public class LoanDomainService {

    private final LoanRepository loanRepository;
    private final LoanProductRepository loanProductRepository;
    private final RepaymentPlanRepository repaymentPlanRepository;
    private final UserRepository userRepository;

    /**
     * 申请贷款
     *
     * @param userId 用户ID
     * @param productId 产品ID
     * @param amount 贷款金额
     * @param period 贷款期限
     * @param purpose 贷款用途
     * @param bankCardId 银行卡ID
     * @return 贷款信息
     */
    @Transactional(rollbackFor = Exception.class)
    public Loan applyLoan(Long userId, Long productId, Long amount, Integer period, String purpose, Long bankCardId) {
        // 检查用户是否存在
        userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException(ResultCode.USER_NOT_FOUND));

        // 检查产品是否存在
        LoanProduct product = loanProductRepository.findById(productId)
                .orElseThrow(() -> new BusinessException(ResultCode.LOAN_PRODUCT_NOT_FOUND));

        // 检查产品是否启用
        if (!product.isEnabled()) {
            throw new BusinessException(ResultCode.LOAN_PRODUCT_DISABLED);
        }

        // 检查贷款金额是否在产品允许范围内
        if (!product.isAmountInRange(amount)) {
            throw new BusinessException(ResultCode.LOAN_AMOUNT_OUT_OF_RANGE);
        }

        // 检查贷款期限是否在产品允许范围内
        if (!product.isPeriodInRange(period)) {
            throw new BusinessException(ResultCode.LOAN_PERIOD_OUT_OF_RANGE);
        }

        // 创建贷款
        Loan loan = new Loan();
        loan.setUserId(userId);
        loan.setLoanNo(loanRepository.generateLoanNo());
        loan.setAmount(amount);
        loan.setPeriod(period);
        loan.setInterestRate(product.getInterestRate());
        loan.setPurpose(purpose);
        loan.setStatus(0); // 申请中
        loan.setApplyTime(LocalDateTime.now());
        loan.setBankCardId(bankCardId);

        // 保存贷款
        return loanRepository.saveAndReturn(loan);
    }

    /**
     * 取消贷款申请
     *
     * @param id 贷款ID
     * @return 是否成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelLoan(Long id) {
        // 检查贷款是否存在
        Loan loan = loanRepository.findById(id)
                .orElseThrow(() -> new BusinessException(ResultCode.LOAN_NOT_FOUND));

        // 检查贷款是否可以取消
        if (!loan.canCancel()) {
            throw new BusinessException(ResultCode.LOAN_CANNOT_CANCEL);
        }

        // 更新贷款状态
        loan.setStatus(2); // 已拒绝
        return loanRepository.update(loan);
    }

    /**
     * 审核贷款
     *
     * @param id 贷款ID
     * @param status 审核状态（2-拒绝，3-通过）
     * @return 是否成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean reviewLoan(Long id, Integer status) {
        // 检查贷款是否存在
        Loan loan = loanRepository.findById(id)
                .orElseThrow(() -> new BusinessException(ResultCode.LOAN_NOT_FOUND));

        // 检查贷款状态是否为申请中或审核中
        if (loan.getStatus() != 0 && loan.getStatus() != 1) {
            throw new BusinessException(ResultCode.LOAN_STATUS_ERROR);
        }

        // 检查审核状态是否合法
        if (status != 2 && status != 3) {
            throw new BusinessException(ResultCode.PARAM_ERROR);
        }

        // 更新贷款状态
        loan.setStatus(status);
        loan.setApproveTime(LocalDateTime.now());
        return loanRepository.update(loan);
    }

    /**
     * 放款
     *
     * @param id 贷款ID
     * @return 是否成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean issueLoan(Long id) {
        // 检查贷款是否存在
        Loan loan = loanRepository.findById(id)
                .orElseThrow(() -> new BusinessException(ResultCode.LOAN_NOT_FOUND));

        // 检查贷款状态是否为已通过
        if (loan.getStatus() != 3) {
            throw new BusinessException(ResultCode.LOAN_STATUS_ERROR);
        }

        // 更新贷款状态
        loan.setStatus(4); // 已放款
        loan.setLoanTime(LocalDateTime.now());
        loan.setRepayStartTime(LocalDateTime.now());

        // 生成还款计划
        List<RepaymentPlan> repaymentPlans = generateRepaymentPlans(loan);

        // 保存贷款和还款计划
        boolean updateResult = loanRepository.update(loan);
        boolean saveResult = repaymentPlanRepository.saveBatch(repaymentPlans);

        return updateResult && saveResult;
    }

    /**
     * 生成还款计划
     *
     * @param loan 贷款信息
     * @return 还款计划列表
     */
    private List<RepaymentPlan> generateRepaymentPlans(Loan loan) {
        List<RepaymentPlan> repaymentPlans = new ArrayList<>();

        // 计算月利率
        BigDecimal monthlyInterestRate = loan.getInterestRate().divide(new BigDecimal("12"), 8, RoundingMode.HALF_UP)
                .divide(new BigDecimal("100"), 8, RoundingMode.HALF_UP);

        // 计算月供
        BigDecimal loanAmount = new BigDecimal(loan.getAmount());
        BigDecimal monthlyPayment = loanAmount.multiply(monthlyInterestRate)
                .multiply(BigDecimal.ONE.add(monthlyInterestRate).pow(loan.getPeriod()))
                .divide(BigDecimal.ONE.add(monthlyInterestRate).pow(loan.getPeriod()).subtract(BigDecimal.ONE), 2, RoundingMode.HALF_UP);

        // 生成还款计划
        BigDecimal remainingPrincipal = loanAmount;
        LocalDate repayDate = LocalDate.now().plusMonths(1);

        for (int i = 1; i <= loan.getPeriod(); i++) {
            // 计算利息
            BigDecimal interest = remainingPrincipal.multiply(monthlyInterestRate).setScale(2, RoundingMode.HALF_UP);
            // 计算本金
            BigDecimal principal = monthlyPayment.subtract(interest).setScale(2, RoundingMode.HALF_UP);
            // 最后一期可能有尾差，确保本金之和等于贷款金额
            if (i == loan.getPeriod()) {
                principal = remainingPrincipal;
                monthlyPayment = principal.add(interest);
            }
            // 更新剩余本金
            remainingPrincipal = remainingPrincipal.subtract(principal);

            // 创建还款计划
            RepaymentPlan repaymentPlan = new RepaymentPlan();
            repaymentPlan.setLoanId(loan.getId());
            repaymentPlan.setUserId(loan.getUserId());
            repaymentPlan.setPeriod(i);
            repaymentPlan.setAmount(monthlyPayment.longValue());
            repaymentPlan.setPrincipal(principal.longValue());
            repaymentPlan.setInterest(interest.longValue());
            repaymentPlan.setRepayDate(repayDate);
            repaymentPlan.setStatus(0); // 未还
            repaymentPlans.add(repaymentPlan);

            // 更新下一期还款日期
            repayDate = repayDate.plusMonths(1);
        }

        return repaymentPlans;
    }

    /**
     * 检查逾期 将超过还款日期且未还款的还款计划标记为逾期
     *
     * @return 是否成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean checkOverdue() {
        // 查询超过还款日期且未还款的还款计划
        List<RepaymentPlan> overduePlans = repaymentPlanRepository.findUnpaidBeforeDate(LocalDate.now());

        // 标记为逾期
        for (RepaymentPlan plan : overduePlans) {
            plan.setStatus(2); // 逾期
            repaymentPlanRepository.update(plan);

            // 更新贷款状态
            Loan loan = loanRepository.findById(plan.getLoanId())
                    .orElseThrow(() -> new BusinessException(ResultCode.LOAN_NOT_FOUND));
            loan.setStatus(7); // 已逾期
            loanRepository.update(loan);
        }

        return true;
    }

    /**
     * 计算贷款
     *
     * @param amount 贷款金额
     * @param period 贷款期限
     * @param interestRate 贷款利率
     * @return 计算结果
     */
    public LoanCalculationResult calculateLoan(Long amount, Integer period, BigDecimal interestRate) {
        // 计算月利率
        BigDecimal monthlyInterestRate = interestRate.divide(new BigDecimal("12"), 8, RoundingMode.HALF_UP)
                .divide(new BigDecimal("100"), 8, RoundingMode.HALF_UP);

        // 计算月供
        BigDecimal loanAmount = new BigDecimal(amount);
        BigDecimal monthlyPayment = loanAmount.multiply(monthlyInterestRate)
                .multiply(BigDecimal.ONE.add(monthlyInterestRate).pow(period))
                .divide(BigDecimal.ONE.add(monthlyInterestRate).pow(period).subtract(BigDecimal.ONE), 2, RoundingMode.HALF_UP);

        // 计算总还款额
        BigDecimal totalPayment = monthlyPayment.multiply(new BigDecimal(period)).setScale(2, RoundingMode.HALF_UP);

        // 计算总利息
        BigDecimal totalInterest = totalPayment.subtract(loanAmount).setScale(2, RoundingMode.HALF_UP);

        // 生成还款计划
        List<RepaymentPlanDetail> repaymentPlanDetails = new ArrayList<>();
        BigDecimal remainingPrincipal = loanAmount;

        for (int i = 1; i <= period; i++) {
            // 计算利息
            BigDecimal interest = remainingPrincipal.multiply(monthlyInterestRate).setScale(2, RoundingMode.HALF_UP);
            // 计算本金
            BigDecimal principal = monthlyPayment.subtract(interest).setScale(2, RoundingMode.HALF_UP);
            // 最后一期可能有尾差，确保本金之和等于贷款金额
            if (i == period) {
                principal = remainingPrincipal;
                monthlyPayment = principal.add(interest);
            }
            // 更新剩余本金
            remainingPrincipal = remainingPrincipal.subtract(principal);

            // 创建还款计划详情
            RepaymentPlanDetail detail = new RepaymentPlanDetail();
            detail.setPeriod(i);
            detail.setAmount(monthlyPayment.longValue());
            detail.setPrincipal(principal.longValue());
            detail.setInterest(interest.longValue());
            detail.setRemainingPrincipal(remainingPrincipal.longValue());
            repaymentPlanDetails.add(detail);
        }

        // 创建计算结果
        LoanCalculationResult result = new LoanCalculationResult();
        result.setAmount(amount);
        result.setPeriod(period);
        result.setInterestRate(interestRate);
        result.setMonthlyPayment(monthlyPayment.longValue());
        result.setTotalPayment(totalPayment.longValue());
        result.setTotalInterest(totalInterest.longValue());
        result.setRepaymentPlan(repaymentPlanDetails);

        return result;
    }

    /**
     * 贷款计算结果
     */
    @Data
    public static class LoanCalculationResult {

        private Long amount;
        private Integer period;
        private BigDecimal interestRate;
        private Long monthlyPayment;
        private Long totalPayment;
        private Long totalInterest;
        private List<RepaymentPlanDetail> repaymentPlan;
    }

    /**
     * 还款计划详情
     */
    @Data
    public static class RepaymentPlanDetail {

        private Integer period;
        private Long amount;
        private Long principal;
        private Long interest;
        private Long remainingPrincipal;
    }
}
